﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Xml.Serialization;
using Win32API;
using System.Runtime.InteropServices;

namespace Kirin.Objects
{
    /// <summary>
    /// Configurable options
    /// </summary>
    public class ConfigOption
    {
        public string name;
        public string currentValue;
        [XmlIgnore]
        public List<string> possibleValues;
        [XmlIgnore]
        public bool immutable;

        public ConfigOption()
        {
            name = "";
            currentValue = "";
            possibleValues = new List<string>();
            immutable = false;
        }
    }

    /// <summary>
    /// D3D rendering configurable options
    /// </summary>
    public class D3D9ConfigOptions
    {
        private List<ConfigOption> configOptions = new List<ConfigOption>();               

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption renderingDevice = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption videoMode = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption fullScreen = new ConfigOption();

        /// <summary>
        /// Render system
        /// </summary>
        private ConfigOption vSync = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption antiAliasing = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption floatingPointMode = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption allowNVPerfHUD = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption sRGBGammaConversion = new ConfigOption();        

        public D3D9ConfigOptions()
        {
            renderingDevice.name = "Rendering Device";
            renderingDevice.possibleValues.Clear();
            renderingDevice.immutable = false;
            configOptions.Add(renderingDevice);

            //for( unsigned j=0; j < driverList->count(); j++ )
            //{
            //    driver = driverList->item(j);
            //    optDevice.possibleValues.push_back( driver->DriverDescription() );...

            videoMode.name = "Video Mode";
            videoMode.currentValue = "800 x 600 @ 32-bit colour";
            videoMode.possibleValues.Clear();
            videoMode.immutable = false;
            configOptions.Add(videoMode);

            fullScreen.name = "Full Screen";
            fullScreen.possibleValues.Add("Yes");
            fullScreen.possibleValues.Add("No");
            fullScreen.currentValue = "Yes";
            fullScreen.immutable = false;
            configOptions.Add(fullScreen);

            vSync.name = "VSync";
            vSync.possibleValues.Add("Yes");
            vSync.possibleValues.Add("No");
            vSync.currentValue = "No";
            vSync.immutable = false;
            configOptions.Add(vSync);

            antiAliasing.name = "Anti aliasing";
            antiAliasing.possibleValues.Add("None");
            antiAliasing.currentValue = "Yes";
            antiAliasing.immutable = false;
            configOptions.Add(antiAliasing);

            floatingPointMode.name = "Anti aliasing";
            floatingPointMode.possibleValues.Add("Fastest");
            floatingPointMode.possibleValues.Add("Consistent");
#if OGRE_DOUBLE_PRECISION
            floatingPointMode.currentValue = "Consistent";
#else
            floatingPointMode.currentValue = "Fastest";
#endif
            floatingPointMode.immutable = false;
            configOptions.Add(floatingPointMode);

            allowNVPerfHUD.name = "Allow NVPerfHUD";
            allowNVPerfHUD.possibleValues.Add("Yes");
            allowNVPerfHUD.possibleValues.Add("No");
            allowNVPerfHUD.currentValue = "No";
            allowNVPerfHUD.immutable = false;
            configOptions.Add(allowNVPerfHUD);

            // SRGB on auto window
            sRGBGammaConversion.name = "sRGB Gamma Conversion";
            sRGBGammaConversion.possibleValues.Add("Yes");
            sRGBGammaConversion.possibleValues.Add("No");
            sRGBGammaConversion.currentValue = "No";
            sRGBGammaConversion.immutable = false;
            configOptions.Add(sRGBGammaConversion);
        }

        public List<ConfigOption> ConfigOptions
        {
            get { return configOptions; }
            set { configOptions = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("Rendering Device.")]
        public ConfigOption RenderingDevice
        {
            get { return renderingDevice; }
            set { renderingDevice = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("Video Mode.")]
        public ConfigOption VideoMode
        {
            get { return videoMode; }
            set { videoMode = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("Full Screen.")]
        public ConfigOption FullScreen
        {
            get { return fullScreen; }
            set { fullScreen = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("VSync.")]
        public ConfigOption VSync
        {
            get { return vSync; }
            set { vSync = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("AntiAliasing")]
        public ConfigOption AntiAliasing
        {
            get { return antiAliasing; }
            set { antiAliasing = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("FloatingPointMode")]
        public ConfigOption FloatingPointMode
        {
            get { return floatingPointMode; }
            set { floatingPointMode = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("AllowNVPerfHUD")]
        public ConfigOption AllowNVPerfHUD
        {
            get { return allowNVPerfHUD; }
            set { allowNVPerfHUD = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("SRGBGammaConversion")]
        public ConfigOption SRGBGammaConversion
        {
            get { return sRGBGammaConversion; }
            set { sRGBGammaConversion = value; }
        }
    }

    /// <summary>
    /// OpenGL rendering configurable options
    /// </summary>
    public class GLConfigOptions
    {
        private List<ConfigOption> configOptions = new List<ConfigOption>();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption fullScreen = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption videoMode = new ConfigOption();
        
        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption colourDepth = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption displayFrequency = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption vSync = new ConfigOption();        

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption fSAA = new ConfigOption();        

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption rTTPreferredMode = new ConfigOption();

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption sRGBGammaConversion = new ConfigOption();        

        public GLConfigOptions()
        {
            // FS setting possibilities
            fullScreen.name = "Full Screen";
            fullScreen.possibleValues.Add("Yes");
            fullScreen.possibleValues.Add("No");
            fullScreen.currentValue = "Yes";
            fullScreen.immutable = false;
            configOptions.Add(fullScreen);

            videoMode.name = "Video Mode";
            videoMode.immutable = false;

            // Enumerate DisplaySettings
            List<DEVMODE> devModes = new List<DEVMODE>();
            User32.EnumDisplaySettings(ref devModes);
            for (int i = 0; i < devModes.Count; ++i)
            {
                DEVMODE devMode = devModes[i];
                string strDevMode = devMode.dmPelsWidth.ToString() + " x " + devMode.dmPelsHeight.ToString();
                if (!videoMode.possibleValues.Contains(strDevMode))
                {
                    videoMode.possibleValues.Add(strDevMode);
                }
            }          
            videoMode.currentValue = videoMode.possibleValues[0];

            configOptions.Add(videoMode);

            colourDepth.name = "Colour Depth";
            colourDepth.immutable = false;
            configOptions.Add(colourDepth);

            displayFrequency.name = "Display Frequency";
            displayFrequency.immutable = false;
            configOptions.Add(displayFrequency);

            vSync.name = "VSync";
            vSync.possibleValues.Add("Yes");
            vSync.possibleValues.Add("No");
            vSync.currentValue = "No";
            vSync.immutable = false;
            configOptions.Add(vSync);

            fSAA.name = "FSAA";
            fSAA.immutable = false;
            fSAA.possibleValues.Add("0");
            fSAA.currentValue = "0";
            configOptions.Add(fSAA);

            RTTPreferredMode.name = "RTT Preferred Mode";
            RTTPreferredMode.possibleValues.Add("FBO");
            RTTPreferredMode.possibleValues.Add("PBuffer");
            RTTPreferredMode.possibleValues.Add("Copy");
            RTTPreferredMode.currentValue = "FBO";
            RTTPreferredMode.immutable = false;
            configOptions.Add(RTTPreferredMode);

            // SRGB on auto window
            sRGBGammaConversion.name = "sRGB Gamma Conversion";
            sRGBGammaConversion.possibleValues.Add("Yes");
            sRGBGammaConversion.possibleValues.Add("No");
            sRGBGammaConversion.currentValue = "No";
            sRGBGammaConversion.immutable = false;
            configOptions.Add(sRGBGammaConversion);
        }

        public List<ConfigOption> ConfigOptions
        {
            get { return configOptions; }
            set { configOptions = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("Full Screen.")]
        public ConfigOption FullScreen
        {
            get { return fullScreen; }
            set { fullScreen = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("Video Mode.")]
        public ConfigOption VideoMode
        {
            get { return videoMode; }
            set { videoMode = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("Colour Depth.")]
        public ConfigOption ColourDepth
        {
            get { return colourDepth; }
            set { colourDepth = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("Display Frequency.")]
        public ConfigOption DisplayFrequency
        {
            get { return displayFrequency; }
            set { displayFrequency = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("VSync.")]
        public ConfigOption VSync
        {
            get { return vSync; }
            set { vSync = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("FSAA.")]
        public ConfigOption FSAA
        {
            get { return fSAA; }
            set { fSAA = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("RTTPreferredMode.")]
        public ConfigOption RTTPreferredMode
        {
            get { return rTTPreferredMode; }
            set { rTTPreferredMode = value; }
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("SRGBGammaConversion.")]
        public ConfigOption SRGBGammaConversion
        {
            get { return sRGBGammaConversion; }
            set { sRGBGammaConversion = value; }
        }
    }

    /// <summary>
    /// Kirin user configurable settings
    /// TODO: Group settings
    /// </summary>
    public class RenderSetting : SettingsBase
    {
#region OGRECFG
        internal D3D9ConfigOptions d3D9ConfigOptions = new D3D9ConfigOptions();
        internal GLConfigOptions gLConfigOptions = new GLConfigOptions();

        [Browsable(true), Category("D3D9")]
        public D3D9ConfigOptions D3D9ConfigOptions
        {
            get { return d3D9ConfigOptions; }
            set { d3D9ConfigOptions = value; }
        }

        [Browsable(true), Category("GL")]
        public GLConfigOptions GLConfigOptions
        {
            get { return gLConfigOptions; }
            set { gLConfigOptions = value; }
        }

        /// <summary>
        /// Render system 
        /// </summary>
        private ConfigOption renderSystem = new ConfigOption();        

        public RenderSetting()
        {
            // render system
            renderSystem.name = "Render System";
            renderSystem.currentValue = "Direct3D9 Rendering Subsystem";
            renderSystem.possibleValues.Add("Direct3D9 Rendering Subsystem");
            renderSystem.possibleValues.Add("OpenGL Rendering Subsystem");
            renderSystem.immutable = false;
        }

        [XmlIgnore]
        [Browsable(true), Category("OGRECFG")]
        [Description("OGRE Render system.")]
        public ConfigOption RenderSystem
        {
            get { return renderSystem; }
            set { renderSystem = value; }
        }
        
#endregion

        // comment out ToString() to have namespace+class name being used as filename
        public override string ToString()
        {
            return "Kirin";
        }
    }
}
